package com.example.audio_test.ui

import android.graphics.SurfaceTexture
import android.opengl.GLES11Ext
import android.opengl.GLES20
import android.opengl.GLSurfaceView
import android.opengl.Matrix
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

/**
 *
 *
 * @author : Kun
 * @date : 2021/7/1
 * @time : 17:28
 */
class MyRender(private val mSurfaceTexture: SurfaceTexture) : GLSurfaceView.Renderer {
    /**
     * 顶点着色器代码片段
     */
    private val vertexShaderCode = "uniform mat4 textureTransform; " +
            "attribute vec2 inputTextureCoordinate; " +
            "attribute vec4 position; " +
            "varying vec2 textureCoordinate; " +
            "void main(){ " +
            " gl_Position = position; " +
            " textureCoordinate = inputTextureCoordinate; " +
            "}"

    private val fragmentShaderCode = "#extension GL_OES_EGL_image_external : require \n" +
            "precision mediump float; " +
            "uniform samplerExternalOES videoTex; " +
            "varying vec2 textureCoordinate; " +
            "void main(){ " +
            "  vec4 tc = texture2D(videoTex,textureCoordinate); " +
//            "  float color = tc.r*0.3 + tc.g *0.59 +tc.b*0.11; " +
//            "  gl_FragColor = vec4(color,color,color,1.0); " +
            "  gl_FragColor = vec4(tc.r,tc.g,tc.b,1.0); " +
            "}"

    private var mPosBuffer: FloatBuffer? = null
    private var mTexBuffer: FloatBuffer? = null

    private val mPosCoordinate = floatArrayOf(-1f, -1f, -1f, 1f, 1f, -1f, 1f, 1f)
    private val mTexCoordinateBackRight = floatArrayOf(1f, 1f, 0f, 1f, 1f, 0f, 0f, 0f)
    private val mTexCoordinateFrontRight = floatArrayOf(0f, 1f, 1f, 1f, 0f, 0f, 1f, 0f)

    var mProgram: Int? = null
    var mBoolean = false

    private var uPosHandle: Int? = null
    private var aTexHandle: Int? = null
    private var mMvpMatrixHandle: Int? = null

    private val mProjectMatrix = FloatArray(16)
    private val mCameraMatrix = FloatArray(16)
    private val mMvpMatrix = FloatArray(16)
    private val mTempMatrix = FloatArray(16)

    var cameraStatus = 0

    companion object {
        fun createOesTextureObject(): Int {
            val tex = IntArray(1)
            //生成一个纹理
            GLES20.glGenTextures(1, tex, 0)
            //将此纹理绑定到外部纹理上
            GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex[0])
            //设置纹理过滤参数
            GLES20.glTexParameterf(
                GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST.toFloat()
            )
            GLES20.glTexParameterf(
                GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR.toFloat()
            )
            GLES20.glTexParameterf(
                GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE.toFloat()
            )
            GLES20.glTexParameterf(
                GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE.toFloat()
            )
            GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0)

            return tex[0]
        }
    }

    init {
        Matrix.setIdentityM(mProjectMatrix, 0)
        Matrix.setIdentityM(mCameraMatrix, 0)
        Matrix.setIdentityM(mMvpMatrix, 0)
        Matrix.setIdentityM(mTempMatrix, 0)
    }

    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
        GLES20.glClearColor(0f, 0f, 0f, 0f)

        val verTexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER)
        GLES20.glShaderSource(verTexShader, vertexShaderCode)
        GLES20.glCompileShader(verTexShader)

        val frameShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER)
        GLES20.glShaderSource(frameShader, fragmentShaderCode)
        GLES20.glCompileShader(frameShader)

        mProgram = GLES20.glCreateProgram()
        GLES20.glAttachShader(mProgram!!, verTexShader)
        GLES20.glAttachShader(mProgram!!, frameShader)
        GLES20.glLinkProgram(mProgram!!)

        GLES20.glDeleteShader(verTexShader)
        GLES20.glDeleteShader(frameShader)

        activeProgram()
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
        Matrix.scaleM(mMvpMatrix, 0, 1f, -1f, 0f)
        val ratio = width.toFloat() / height
        Matrix.orthoM(mProjectMatrix, 0, -1f, 1f, -ratio, ratio, 3f, 7f)
        Matrix.setLookAtM(mCameraMatrix, 0, 0f, 0f, 3f, 0f, 0f, 0f, 0f, 1f, 0f)
        Matrix.multiplyMM(mMvpMatrix, 0, mProjectMatrix, 0, mCameraMatrix, 0)
    }

    override fun onDrawFrame(gl: GL10?) {
        if (mBoolean) {
            activeProgram()
            mBoolean = false
        }

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT)
        mSurfaceTexture.updateTexImage()
        GLES20.glUniformMatrix4fv(mMvpMatrixHandle!!, 1, false, mMvpMatrix, 0)
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, mPosCoordinate.size / 2)
    }

    fun activeProgram() {
        GLES20.glUseProgram(mProgram!!)

        uPosHandle = GLES20.glGetAttribLocation(mProgram!!, "position")
        aTexHandle = GLES20.glGetAttribLocation(mProgram!!, "inputTextureCoordinate")
        mMvpMatrixHandle = GLES20.glGetUniformLocation(mProgram!!, "textureTransform")

        mPosBuffer = convertToFloatBuffer(mPosCoordinate)
        mTexBuffer =
            convertToFloatBuffer(if (cameraStatus == 0) mTexCoordinateBackRight else mTexCoordinateFrontRight)

        GLES20.glVertexAttribPointer(uPosHandle!!, 2, GLES20.GL_FLOAT, false, 0, mPosBuffer)
        GLES20.glVertexAttribPointer(aTexHandle!!, 2, GLES20.GL_FLOAT, false, 0, mTexBuffer)

        GLES20.glEnableVertexAttribArray(uPosHandle!!)
        GLES20.glEnableVertexAttribArray(aTexHandle!!)

    }

    private fun convertToFloatBuffer(buffer: FloatArray): FloatBuffer {
        val buffer1 = ByteBuffer.allocateDirect(buffer.size * 4)
        buffer1.order(ByteOrder.nativeOrder())
        val b = buffer1.asFloatBuffer()
        b.put(buffer)
        b.position(0)
        return b
    }
}